package product

import (
	"context"
	"reflect"
	"strings"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/sagoo-cloud/sagooiot/api/v1/product"
	"github.com/sagoo-cloud/sagooiot/internal/consts"
	"github.com/sagoo-cloud/sagooiot/internal/dao"
	"github.com/sagoo-cloud/sagooiot/internal/model"
	"github.com/sagoo-cloud/sagooiot/internal/model/entity"
	"github.com/sagoo-cloud/sagooiot/internal/service"
)

type sProductDevAsset struct{}

func sProductDevAssetNew() *sProductDevAsset {
	return &sProductDevAsset{}
}
func init() {
	service.RegisterProductDevAsset(sProductDevAssetNew())
}

// GetDevAssetList 获取列表数据
func (s *sProductDevAsset) GetDevAssetList(ctx context.Context, in *model.GetDevAssetListInput) (total, page int, list []*model.DevAssetOutput, err error) {
	err = g.Try(ctx, func(ctx context.Context) {
		m := dao.DevAsset.Ctx(ctx)
		total, err = m.Count()
		if err != nil {
			err = gerror.New("获取总行数失败")
			return
		}
		page = in.PageNum
		if in.PageSize == 0 {
			in.PageSize = consts.PageSize
		}
		if in.KeyWord != "" {
			m = m.WhereOrLike(dao.DevAsset.Columns().DeviceName, "%"+in.KeyWord+"%")
			m = m.WhereOrLike(dao.DevAsset.Columns().DeviceKey, "%"+in.KeyWord+"%")
			m = m.WhereOrLike(dao.DevAsset.Columns().DeviceNumber, "%"+in.KeyWord+"%")
		}
		err = m.Page(page, in.PageSize).Order("created_at desc").Scan(&list)
		if err != nil {
			err = gerror.New("获取数据失败")
		}
	})
	return
}

// GetDevAssetByDevKey 获取指定deviceKey的数据
func (s *sProductDevAsset) GetDevAssetByDevKey(ctx context.Context, deviceKey string) (out *product.GetDevAssetByDevKeyRes, err error) {
	asset := entity.DevAsset{}
	err = dao.DevAsset.Ctx(ctx).Where(dao.DevAsset.Columns().DeviceKey, deviceKey).Scan(&asset)
	if err != nil {
		return
	}
	out = new(product.GetDevAssetByDevKeyRes)
	gconv.Scan(asset, out)
	var meta []entity.DevAssetMetadata
	err = dao.DevAssetMetadata.Ctx(ctx).Where(dao.DevAssetMetadata.Columns().ProductKey, asset.ProductKey).Scan(&meta)
	if err != nil {
		return
	}
	s.fill(&asset, meta, out)
	return
}

func (s *sProductDevAsset) fill(en *entity.DevAsset, meta []entity.DevAssetMetadata, out *product.GetDevAssetByDevKeyRes) {
	typ := reflect.TypeOf(en).Elem()
	val := reflect.ValueOf(en).Elem()
	for i := 0; i < len(meta); i++ {
		for k := 0; k < typ.NumField(); k++ {
			field := typ.Field(k)
			if meta[i].FieldName == strings.ToLower(field.Name) {
				res := product.MetaDataValue{}
				gconv.Scan(meta[i], &res)
				res.Value = val.Field(k).String()
				out.Data = append(out.Data, res)
			}
		}
	}
}

// AddDevAsset 添加数据
func (s *sProductDevAsset) AddDevAsset(ctx context.Context, in *product.AddDevAssetReq, createdBy int) (err error) {

	var insert entity.DevAsset
	gconv.Scan(in, &insert)
	insert.CreatedBy = uint(createdBy)
	for _, v := range in.Data {
		s.setFieldValue(v, &insert)
	}
	_, err = dao.DevAsset.Ctx(ctx).Insert(insert)
	return
}

func (s *sProductDevAsset) setFieldValue(v product.MetaDataValue, en *entity.DevAsset) {
	t := reflect.TypeOf(en).Elem()
	val := reflect.ValueOf(en).Elem()
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		if strings.ToLower(field.Name) == v.FieldName {
			temp := reflect.ValueOf(v.Value)
			val.Field(i).Set(temp)
		}
	}
}

// EditDevAsset 修改数据
func (s *sProductDevAsset) EditDevAsset(ctx context.Context, in *product.EditDevAssetReq, updatedBy int) (err error) {
	var update entity.DevAsset
	gconv.Scan(in, &update)
	update.UpdatedBy = uint(updatedBy)
	for _, v := range in.Data {
		s.setFieldValue(v, &update)
	}
	dao.DevAsset.Ctx(ctx).FieldsEx(dao.DevAsset.Columns().Id).Where(dao.DevAsset.Columns().Id, in.Id).Update(update)
	return
}

// DeleteDevAsset 删除数据
func (s *sProductDevAsset) DeleteDevAsset(ctx context.Context, Ids []int) (err error) {
	_, err = dao.DevAsset.Ctx(ctx).Delete(dao.DevAsset.Columns().Id+" in (?)", Ids)
	return
}
